#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Create by zhang
# Create on 2022/6/24 17:40
from domain.report.common.period_enum import PeriodEnum
from domain.report.common.period_util import get_pre_period
from domain.report.entity.balance_sheet import BalanceSheet
from domain.report.entity.cash import Cash
from domain.report.entity.profit import Profit


class ReportAgg:
    def __init__(self, stock_code:str, year:int, period:PeriodEnum, is_consolidate:bool=False):
        self.stock_code = stock_code
        self.year = year
        self.period = period
        self.is_consolidate = is_consolidate
        self.balance_sheet = BalanceSheet.query(stock_code, year, period, is_consolidate)
        self.cash = Cash.query(stock_code, year, period, is_consolidate)
        self.profit = Profit.query(stock_code, year, period, is_consolidate)

    def get_net_profit_available_for_common_shareholders(self):
        """
        可供普通股股东分配的净利润(Net profit available for distribution to common shareholders)
        可供普通股股东分配的净利润 = 年初未分配利润金额 + 本年度实现的净利润 - 优先股应分的利润
        """
        year, period = get_pre_period(year=self.year, period=self.period)
        pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return pre_balance_sheet.undistr_porfit + self.profit.net_profit

    def coreP_nocf_ratio(self):
        """
        核心利润获现率（net operating cash flows to core profit ratio)
        核心利润获现率 = 经营活动产生的现金流量净额/核心利润
        """
        return self.cash.n_cashflow_act/self.profit.get_core_profit()

    def return_on_operating_assets(self):
        """
        经营性资产报酬率（return on operating assets）
        经营性资产报酬率 = 核心利润/平均经营性资产
        平均经营性资产 = 经营性资产年初余额 - 经营性资产年末余额
        """
        if self.period == PeriodEnum.year:
            pre_balance_sheet = BalanceSheet.query(self.stock_code, self.year - 1, self.period)
            return self.profit.get_core_profit()/((self.balance_sheet.get_operating_assets() + pre_balance_sheet.get_operating_assets())/2)
        return None

    def return_on_total_assets(self):
        """
        总资产报酬率（return on total assets）：对企业整体盈利能力的衡量
        总资产报酬率 = 息税前利润/平均总资产
        在不考虑利息费用和纳税因素而只考虑经营情况时，这个比率反应管理层对所有资产实施管理所产生的效益，即管理层利用企业现有资源创造价值的能力。
        """
        if self.period == PeriodEnum.year:
            pre_balance_sheet = BalanceSheet.query(self.stock_code, self.year - 1, self.period)
        return self.profit.get_earnings_before_interest()/((self.balance_sheet.total_assets + pre_balance_sheet.total_assets)/2)

    def return_on_common_equity(self):
        """
        股东权益报酬率（return on common equity）
        股东权益报酬率 = 可供普通股股东分配的净利润/平均普通股股东权益
        可供普通股股东分配的净利润 = 息税后净利润 - 优先股股利
        息税后净利润 = 净利润 = 利润总额 - 所得税费用
        普通股股东权益 ？=
        """
        pass

    def accounts_receivable_turnover(self):
        """
        应收账款周转率（accounts receivable turnover）
        应收账款周转率 = 赊销净额/平均应收账款
        平均应收账款 = （年初 + 年末）/2
        """
        if self.period == PeriodEnum.year:
            pre_balance_sheet = BalanceSheet.query(self.stock_code, self.year - 1, self.period)
        return self.profit.get_net_sales_on_credit()/((self.balance_sheet.account_receivable + pre_balance_sheet.account_receivable) / 2)

    def trade_credit_turnover(self):
        """
        商业债券周转率（trade credit turnover）
        商业债券周转率 = 赊销净额/(平均应收账款+平均应收票据)
        如果企业的应收票据占商业债券的比重较大，也就是说推动营业收入的主要是应收票据而非应收帐款，若仍用应收账款周转率指标来衡量公司应收账款的回收速度就会有失偏颇。
        """
        if self.period == PeriodEnum.year:
            pre_balance_sheet = BalanceSheet.query(self.stock_code, self.year - 1, self.period)
        return self.profit.get_net_sales_on_credit()/((self.balance_sheet.account_receivable + pre_balance_sheet.account_receivable) / 2 + (self.balance_sheet.bills_receivable + pre_balance_sheet.bills_receivable) / 2)

    def average_collection_period(self):
        """
        平均收账期（average collection period）
        平均收账期 = 平均应收账款/平均日赊销额 = 365/应收账款周转率
        注意：
            1. 该公式假设企业的应收票据一般规模不大（因为应收票据也推动了赊销收入），在应收票据规模较大时，应该为商业债券周转率；
            2. 应收账款应该用减除坏账准备之前的”原值“金额（因为企业真正周转和回收的不是净值，而是原值）
            3. 在实施增值税的条件下，销售额的项目还应该乘以（1+增值税税率），这是因为债权中包括销项增值税。
        """
        # TODO 判断使用 应收账款周转率 还是 商业债券周转率
        # TODO 考虑实施增值税的情况
        return 365/self.accounts_receivable_turnover()

    def inventory_turnover(self, is_year:bool=False):
        """
        存货周转率（inventory turnover）
        存货周转率 = 营业成本/平均存货
        营业成本是对应的年、季、月营业成本
        平均存货是对应年、季、月平均存货
        需要根据企业的特点选择合适的存货计算周期，比如很多企业的存货存在季节性
        """
        if is_year:
            pre_balance_sheet = BalanceSheet.query(self.stock_code, self.year - 1, PeriodEnum.year)
        else:
            year , period = get_pre_period(year=self.year, period=self.period)
            pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return self.profit.operating_cost / ((self.balance_sheet.inventories + pre_balance_sheet.inventories) / 2)

    def inventory_turnover_days(self, is_year:bool=False):
        """
        存货周转天数（Inventory Turnover Days）,实际上是 存货周转率 的另一种表达方式
        存货周转天数 = 平均存货/平均日营业成本 = 365/存货周转率
        """
        return 365/self.inventory_turnover_days(is_year)

    def business_cycle(self, is_year:bool=False):
        """
        企业营业周期 = 平均收账期 + 存货周转天数
        """
        return self.average_collection_period() + self.inventory_turnover_days(is_year)

    def operating_assets_turnover(self):
        """
        经营性资产周转率（operating assets turnover）
        经营性资产周转率 = 营业收入/平均经营性资产
        平均经营性资产 = （期初 + 期末）/2
        由于只有经营性资产才能带来营业收入，创造核心利润，因此，此指标可以考察企业经营性资产的周转效率，可以剔除投资性资产的干扰，
        更加客观、直接地反映企业管理层在自身的经营活动中对资产运营效率的管理能力。
        """
        year, period = get_pre_period(year=self.year, period=self.period)
        pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return self.profit.revenue/((self.balance_sheet.get_operating_assets() + pre_balance_sheet.get_operating_assets())/2)

    def fixed_assets_turnover(self):
        """
        固定资产周转率（fixed assets turnover）
        固定资产周转率 = 营业收入/平均固定资产原值
        平均固定资产原值 = （期初 + 期末）/2
        这个指标可以粗略地计算企业固定资产创造收入的能力反映企业管理层管理企业固定资产运营的能力。
        用原值计算出来的周转率可以恰当地反映企业对固定资产的运用状况。否则就会出现这样的情况：企业相邻两年的营业收入完全一样，但由于第二年企业计提
        了折旧而导致净值减少，结果用净值计算出来的周转率第二年高于第一年
        """
        year, period = get_pre_period(year=self.year, period=self.period)
        pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return self.profit.revenue/((self.balance_sheet.get_fixed_assets_original_value() + pre_balance_sheet.get_fixed_assets_original_value())/2)

    def total_assets_turnover(self):
        """
        总资产周转率（total assets turnover）
        总资产周转率 = 营业收入/平均总资产
        平均总资产 = （期初 + 期末）/2
        这个指标可以粗略地（因为资产的组成很复杂）计量企业资产创造收入的能力，反映企业管理层管理企业资产运营的能力
        """
        year, period = get_pre_period(year=self.year, period=self.period)
        pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return self.profit.revenue/((self.balance_sheet.total_assets + pre_balance_sheet.total_assets)/2)

    def operating_cash_flow_to_liabilities(self):
        """
        现金与负债总额比率（operating cash flow to liabilities）是指经营活动现金净流量与平均总负债额的比率。
        现金与负债总额比率 = 经营活动现金净流量/平均总负债
        现金与负债总额比率反映了企业依据自身创造现金的能力所能够承担债务规模的大小。
        一般而言，该比率越高，企业承担债务的能力就越强；该比率越低，企业承担债务的能力就越弱。
        """
        year, period = get_pre_period(year=self.year, period=self.period)
        pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return self.cash.n_cashflow_act/((self.balance_sheet.total_liab + pre_balance_sheet.total_liab)/2)

    def operating_cash_flow_to_oprating_assets(self):
        """
        经营活动资产现金回收比率（operating cash flow to oprating assets）
        经营活动资产现金回收比率 = 经营活动现金净流量/平均经营性资产
        该比率反映了一定时期经营性资产创造现金的能力
        与同行平均数值相比，该数值越大，表明企业经营性资产整体获现质量越好
        """
        year, period = get_pre_period(year=self.year, period=self.period)
        pre_balance_sheet = BalanceSheet.query(self.stock_code, year, period)
        return self.cash.n_cashflow_act / ((self.balance_sheet.get_operating_assets() + pre_balance_sheet.get_operating_assets()) / 2)

    def cash_inflow_from_operations_to_sales(self):
        """
        收入现金比率（cash inflow from operations to sales）
        收入现金比率 = 经营活动现金净流入/营业收入
        该比率反映了企业从每一元营业收入中所实现的净现金收入；从另一个角度分析，该比率体现了企业应收账款回收的效率。
        该比率越大，表明企业的收入质量越高，企业应收款回收的效率越高。
        """
        return self.cash.n_cashflow_act/self.profit.revenue